﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Library.Test.Logic
{

    //plain delegate 与 event的关系类似于field与Property（实事上前者就是field 字段 ，或者我们可以把event看成是一种特殊的Property属性）
    //正是由于1#，在使用上，plain delegate几乎没有任何限制，而event则有严格的限制（只能用在+=和-=的左边）
    //事件与委托的区别

    //event更面向对象一些。
    //当我们需要灵活时，直接使用plain delegate; 反之，需要严格的控制时，使用event。
    //由于event不能使用赋值运算符，因此有时我们要求一个事件在任何时刻只能有一个响应方法时，我们使用plain delegate更为方便。

    public delegate void TestDelegate(string s);

    public interface ITest
    {
        //【区别】 1. event可以用在interface中，而plain delegate不可以（因为它是field）
        event TestDelegate TestE;   // Passed
        //TestDelegate TestD;       // Error: Interfaces cannot contain fields
    }

    public class Parent
    {
        public TestDelegate TestD;

        public event TestDelegate TestE;
        
        protected void RaiseTestE(string s)
        {
            TestE(s);//事件的EventAndDelegate.Parent.TestE'只能在'EventAndDelegate.Parent'类型中使用
        }
    }

    public class Child : Parent
    {
        void ChildFunc()
        {
            // 【区别】 2. event不允许在声明它的class之外（即使是子类）被调用（除此之外只能用于+=或-=），而plain delegate则允许
            TestD("OK");        // Passed

            //TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
                                //        the left hand side of += or -= (except when used from within
                                //        the type 'EventAndDelegate.Parent')

            //【补充】 在子类中要触发父类声明的event，通常的做法是在父类中声明一个protected的Raisexxx方法供子类调用
            RaiseTestE("OK");   // The class 'EventAndDelegate.Child' can only call the
                                // 'EventAndDelegate.ParentRaiseTestE' method to raise the event
                                // 'EventAndDelegate.Parent.TestE'

            //【区别】 同2#
            object o1 = TestD.Target;
            //object o2 = TestE.Target; // The class 'EventAndDelegate.Child' can only call the
                                        // 'EventAndDelegate.ParentRaiseTestE' method to raise the event
                                        // 'EventAndDelegate.Parent.TestE'

            // 【区别】 同2#
            TestD.DynamicInvoke("OK");
            //TestE.DynamicInvoke("OK"); // The class 'EventAndDelegate.Child' can only call the
                                         // 'EventAndDelegate.ParentRaiseTestE' method to raise the event
                                         // 'EventAndDelegate.Parent.TestE'
        }
    }

    public class Other
    {
        private static void Execute()
        {
            Parent p = new Parent();

            p.TestD += new TestDelegate(p_Test1);   // Passed
            p.TestE += new TestDelegate(p_Test1);   // Passed

            // 【区别】 3. event不允许使用赋值运算符，而plain delegate则允许。
            //             注意，对plain delegate，使用赋值运算符意味着进行了一次替换操作！
            p.TestD = new TestDelegate(p_Test2);   // Passed
            //p.TestE = new TestDelegate(p_Test2);   // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
                                                   //        the left hand side of += or -= (except when used from within
                                                   //        the type 'EventAndDelegate.Parent')

            // 【区别】 同2#
            p.TestD("OK");      // Passed
            //p.TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
                                //        the left hand side of += or -= (except when used from within
                                //        the type 'EventAndDelegate.Parent')
        }

        private static void p_Test1(string s)
        {
            Console.WriteLine("p_Test1: " + s);
        }

        private static void p_Test2(string s)
        {
            Console.WriteLine("p_Test2: " + s);
        }
    }
}
